<?php
/**
 * Created by PhpStorm.
 * User: yf
 * Date: 2018/5/28
 * Time: 下午6:33
 */

namespace EasySwoole\EasySwoole;


use App\Crontab\DailyTask;
use App\Crontab\FinanceTask;
use App\Crontab\GuessTask;
use App\Crontab\MessageTask;
use App\Crontab\OrderTask;
use App\Model\Finance\Util;
use App\Utility\FinanceUtil;
use App\Utility\Pool\MysqlPool;
use App\Utility\Pool\RedisPool;
use App\Utility\Queue\Queue;
use App\Utility\Queue\QueueProcess;
use App\WebSocket\WebSocketEvents;
use App\WebSocket\WebSocketParser;
use App\Crontab\RedPackTask;
use EasySwoole\Component\Pool\PoolManager;
use EasySwoole\Component\Timer;
use EasySwoole\EasySwoole\Crontab\Crontab;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\Http\Request;
use EasySwoole\Http\Response;
use EasySwoole\RedisPool\Redis;
use EasySwoole\Socket\Dispatcher;

class EasySwooleEvent implements Event
{

    public static function initialize()
    {
        // TODO: Implement initialize() method.
        date_default_timezone_set('Asia/Shanghai');

        /**
         * Mysql协程连接池
         */
        $mysqlConf = PoolManager::getInstance()->register(MysqlPool::class, Config::getInstance()->getConf('MYSQL.POOL_MAX_NUM'));
        if ($mysqlConf === null) {
            //当返回null时,代表注册失败,无法进行再次的配置修改
            //注册失败不一定要抛出异常,因为内部实现了自动注册,不需要注册也能使用
            throw new \Exception('注册失败!');
        }
        //设置其他参数
        $mysqlConf->setMaxObjectNum(20)->setMinObjectNum(5);

        /**
         * REDIS协程连接池
         */
        PoolManager::getInstance()->register(RedisPool::class, Config::getInstance()->getConf('REDIS.POOL_MAX_NUM'));

    }

    public static function mainServerCreate(EventRegister $register)
    {
        // TODO: Implement mainServerCreate() method.

        // TODO: Implement mainServerCreate() method.
        /**
         * **************** websocket控制器 **********************
         */
        // 创建一个 Dispatcher 配置
        $conf = new \EasySwoole\Socket\Config();
        // 设置 Dispatcher 为 WebSocket 模式
        $conf->setType(\EasySwoole\Socket\Config::WEB_SOCKET);
        // 设置解析器对象
        $conf->setParser(new WebSocketParser());
        // 创建 Dispatcher 对象 并注入 config 对象
        $dispatch = new Dispatcher($conf);
        // 给server 注册相关事件 在 WebSocket 模式下  on message 事件必须注册 并且交给 Dispatcher 对象处理
        $register->set(EventRegister::onMessage, function (\swoole_websocket_server $server, \swoole_websocket_frame $frame) use ($dispatch) {
            $dispatch->dispatch($server, $frame->data, $frame);
        });
        // 注册服务事件
        $register->add(EventRegister::onOpen, [WebSocketEvents::class, 'onOpen']);
        $register->add(EventRegister::onClose, [WebSocketEvents::class, 'onClose']);

        /**
         * **************** 消息队列（处理公众号推送，发送红包） **********************
         **/
        Redis::getInstance()->register('queue', new \EasySwoole\RedisPool\Config());
        $driver = new \EasySwoole\Queue\Driver\Redis('queue', 'queue');
        Queue::getInstance($driver);
        //消费者(推送预约，推送处理提现)
        $process = new QueueProcess('QueueProcess', null, false, 2, true);
        $process2 = new QueueProcess('QueueProcess', null, false, 2, true);
        ServerManager::getInstance()->addProcess($process);
        ServerManager::getInstance()->addProcess($process2);

        /**
         * **************** 聊天信息推送 **********************
         */
        $register->add(EventRegister::onWorkerStart, function (\swoole_websocket_server $server, $workerId) {
            //如何避免定时器因为进程重启而丢失
            //例如在第一个进程 添加一个10秒的定时器
            if ($workerId == 0) {
                //初始化红包列表
                Util::redpackInit(true);

                //加载机器人列表
                $databotlist = Util::robotInit();


                $tempbotlist = array();
                $msglsit = [
                    '稍微绿绿盘，让我低吸可好？', '成交量还是差一点，没戏。', '希望今天能猜中，就差这个连胜了！', '指数要企稳，肯定看券商！', '我说话跳水，你信不信？', '狗哥说看空，我不敢说话。', '涨呀大盘', '赢够了，兑红包去..', '跌跌跌，别说话', '真够墨迹的', '心情不错，所以我看空', '补仓，马上补仓！', '一万点！！', '主力都跑了，你们还看多？', '韭菜们准备好被割..', '还是我的茅台给力', '认了，高开低走..', '真没意思。。', '又被吃了100分', '有分就是好，左一个红包，右一个红包', '我就猜跌，为猜涨跌活动做贡献', '生活也许就是这样，输输赢赢..', '涨不起来了，平盘怎么搞？', '就是不懂，真难受', '股侠看多，你们怎么看？', '还是趋势股猛！', '红了，真的红了！', '你以为就这样完了，等炸', '外资才是最聪明的，又在抄底', '奉劝游资们做个好人。。',
                ];
                while (count($tempbotlist) < 5) {
                    $data['type'] = 'msg';
                    $data['avatar'] = $databotlist[rand(0, count($databotlist) - 1)]['avatar'];
                    $data['txt'] = $msglsit[rand(0, count($msglsit) - 1)];
                    array_push($tempbotlist, $data);
                }


                Timer::getInstance()->loop(6 * 1000, function () use ($server, $databotlist, $tempbotlist, $msglsit) {
                    $redis = RedisPool::defer();
                    $clist = $server->getClientList();
                    $data['type'] = 'msg';
                    $data['avatar'] = $databotlist[rand(0, count($databotlist) - 1)]['avatar'];
                    $data['txt'] = $msglsit[rand(0, count($msglsit) - 1)];
                    //记录最近5条
                    array_shift($tempbotlist);
                    array_push($tempbotlist, $data);
                    $redis->set('cz_finance_msg_cache', json_encode($tempbotlist));
                    if (is_array($clist)) {
                        foreach ($clist as $fd) {
                            $server->push($fd, json_encode($data));//发送消息
                        }
                    }
                });
                Timer::getInstance()->loop(90 * 1000, function () use ($server) {
                    //重置
                    $score = Util::score();
                    $clist = $server->getClientList();
                    if (is_array($clist)) {
                        foreach ($clist as $fd) {
                            $server->push($fd, json_encode($score));//发送消息
                        }
                    }
                });
                //更新K-LINE
                Timer::getInstance()->loop(180 * 1000, function () use ($server) {

                    //开盘时间才推

                    $is_guess = FinanceUtil::is_finance();

                    if ($is_guess) {
                        $redis = RedisPool::defer();
                        //重置

                        $json = file_get_contents("http://img1.money.126.net/data/hs/time/today/0000001.json");
                        $dataKline['type'] = 'k-line';
                        $dataKline['val'] = $json;
                        $redis->set('cz_k_line_cache', $json);
                        $clist = $server->getClientList();
                        if (is_array($clist)) {
                            foreach ($clist as $fd) {
                                $server->push($fd, json_encode($dataKline));//发送消息
                            }
                        }
                    }
                });

            }

        });


        /**
         * **************** 定时器 **********************
         */
        //提现每3分钟处理一次
        Crontab::getInstance()->addTask(OrderTask::class);

        //消息推送10点
        Crontab::getInstance()->addTask(MessageTask::class);

        //统计 (周一至周五 15点3分统计)
        Crontab::getInstance()->addTask(GuessTask::class);

        //每日任务
        Crontab::getInstance()->addTask(DailyTask::class);

        //红包
        Crontab::getInstance()->addTask(RedPackTask::class);
        Crontab::getInstance()->addTask(FinanceTask::class);

        //禁号检测
        //Crontab::getInstance()->addTask(DenyRobot::class);

        /**
         * ****************  mysql 热启动  ****************
         */
        $register->add($register::onWorkerStart, function (\swoole_server $server, int $workerId) {
            if ($server->taskworker == false) {
                //每个worker进程都预创建连接
                PoolManager::getInstance()->getPool(MysqlPool::class)->preLoad(5);//最小创建数量
            }
        });

        /**
         * ****************   服务热重启    ****************
         */
        //$swooleServer = ServerManager::getInstance()->getSwooleServer();
        //$swooleServer->addProcess((new HotReload('HotReload', ['disableInotify' => false]))->getProcess());

    }

    public static function onRequest(Request $request, Response $response): bool
    {
        // TODO: Implement onRequest() method.
        return true;
    }

    public static function afterRequest(Request $request, Response $response): void
    {
        // TODO: Implement afterAction() method.
    }
}